#include "../stdafx.h"
#include "Grid.h"
#include <iostream>
#include <sstream>
#include <stdio.h>
#include "TileFactory.h"

namespace Model{

Grid::Grid()
{
}
/**
 * Initialize the grid
 */
void Grid::init()
{
	MobileTile* currentMobileTile;

	TileFactory* tileFactory=new TileFactory();
	Tile* tileMatrix[NB_SIDE_TILE][NB_SIDE_TILE];
	/*
	tileMatrix[0][0]= tileFactory->createTile(FIXED,crossTile);
	tileMatrix[0][1]= tileFactory->createTile(MOBILE,crossTile);
	tileMatrix[0][2]= tileFactory->createTile(FIXED,crossTile);

	tileMatrix[1][0]= tileFactory->createTile(MOBILE,crossTile);
	tileMatrix[1][1]= tileFactory->createTile(MOBILE,crossTile);
	tileMatrix[1][2]= tileFactory->createTile(MOBILE,crossTile);

	tileMatrix[2][0]= tileFactory->createTile(FIXED,crossTile);
	tileMatrix[2][1]= tileFactory->createTile(MOBILE,crossTile);
	tileMatrix[2][2]= tileFactory->createTile(FIXED,crossTile);
	*/

	for(int i=0;i<NB_SIDE_TILE;i++){
		for(int j=0; j<NB_SIDE_TILE; j++){
			tileMatrix[i][j]=tileFactory->createTile(MOBILE,crossTile);
		}
	}
tileMatrix[2][5]=tileFactory->createTile(MOBILE,bentTile);
	//Initialisation de tous les pointeurs,
	//du vector tiles et de la map pushableTiles
	for(int i=0; i<NB_SIDE_TILE;++i){
		for(int j=0; j<NB_SIDE_TILE; ++j){
			currentMobileTile = dynamic_cast<MobileTile*>(tileMatrix[i][j]);
			if(i==0){
				tileMatrix[i][j]->setLeftNeighbor(NULL);
				if(currentMobileTile) this->pushableTiles.insert(pair<int,MobileTile*>(j,currentMobileTile));
			}
			else{
				tileMatrix[i][j]->setLeftNeighbor(tileMatrix[i-1][j]);
			}
			if(i==NB_SIDE_TILE-1){
				tileMatrix[i][j]->setRightNeighbor(NULL);
				if(currentMobileTile) this->pushableTiles.insert(pair<int,MobileTile*>(-j,currentMobileTile));
			}
			else{
				tileMatrix[i][j]->setRightNeighbor(tileMatrix[i+1][j]);

			}
			if(j==0){
				tileMatrix[i][j]->setUpNeighbor(NULL);
				if(currentMobileTile) this->pushableTiles.insert(pair<int,MobileTile*>(NB_SIDE_TILE-1+i,currentMobileTile));
			}
			else{
				tileMatrix[i][j]->setUpNeighbor(tileMatrix[i][j-1]);
			}
			if(j==NB_SIDE_TILE-1){
				tileMatrix[i][j]->setDownNeighbor(NULL);
				if(currentMobileTile) this->pushableTiles.insert(pair<int,MobileTile*>(-(NB_SIDE_TILE-1+i),currentMobileTile));
			}
			else{
				tileMatrix[i][j]->setDownNeighbor(tileMatrix[i][j+1]);
			}
			if(i==0 && j==0) this->firstTile=tileMatrix[i][j];
			this->tiles.push_back(tileMatrix[i][j]);
		}
	}
}

Grid::~Grid(void)
{
}
/**
 * @param tileId : the id of a pushable tile
 * @return the pushable tile
 */
MobileTile* Grid::getPushableTile(int tileId)
{
	return this->pushableTiles[tileId];
}
/**
 * Recursive function which push every tile in a row or a column until the end of
 * the row or column.
 * @return the new free tile
 */
MobileTile* Grid::pushTile(MobileTile* freeTile, int pushableTileId)
{

	MobileTile* tileToPush = pushableTiles[pushableTileId];
	MobileTile* newFreeTile;
	this->pushableTiles[pushableTileId]=freeTile; //on remplace l'ancienne tuile poussable par la tuile inssere

	if(tileToPush->rightNeighbor()==NULL){
		freeTile->setLeftNeighbor(tileToPush);
		freeTile->leftNeighbor()->setRightNeighbor(freeTile);
		newFreeTile = freeTile->goLeft();
		this->pushableTiles[-pushableTileId]=static_cast<MobileTile*>(newFreeTile->rightNeighbor());
		newFreeTile->rightNeighbor()->setLeftNeighbor(NULL);
	}
	if(tileToPush->leftNeighbor()==NULL){
		freeTile->setRightNeighbor(tileToPush);
		freeTile->rightNeighbor()->setLeftNeighbor(freeTile);
		newFreeTile = freeTile->goRight();
		this->pushableTiles[-pushableTileId]=static_cast<MobileTile*>(newFreeTile->leftNeighbor());
		newFreeTile->leftNeighbor()->setRightNeighbor(NULL);
	}
	if(tileToPush->upNeighbor()==NULL){
		freeTile->setDownNeighbor(tileToPush);
		freeTile->downNeighbor()->setUpNeighbor(freeTile);
		newFreeTile = freeTile->goDown();
		this->pushableTiles[-pushableTileId]=static_cast<MobileTile*>(newFreeTile->upNeighbor());
		newFreeTile->upNeighbor()->setDownNeighbor(NULL);
	}
	if(tileToPush->downNeighbor()==NULL){
		freeTile->setUpNeighbor(tileToPush);
		freeTile->upNeighbor()->setDownNeighbor(freeTile);
		newFreeTile = freeTile->goUp();
		this->pushableTiles[-pushableTileId]=static_cast<MobileTile*>(newFreeTile->downNeighbor());
		newFreeTile->downNeighbor()->setUpNeighbor(NULL);
	}

	newFreeTile->setRightNeighbor(NULL);
	newFreeTile->setLeftNeighbor(NULL);
	newFreeTile->setUpNeighbor(NULL);
	newFreeTile->setDownNeighbor(NULL);
	return newFreeTile;
}

Grid* Grid::clone()
{
	return NULL;
}
/**
 * move the iterator's ec one tile up
 */
void Grid::GridIterator::up()
{
	if(this->ec->upNeighbor()!=NULL){
		this->ec=this->ec->upNeighbor();
	}
}
/**
 * move the iterator's ec one tile down
 */
void Grid::GridIterator::down()
{
	if(this->ec->downNeighbor()!=NULL){
		this->ec=this->ec->downNeighbor();
	}
}
/**
 * move the iterator's ec one tile left
 */
void Grid::GridIterator::left()
{
	if(this->ec->leftNeighbor()!=NULL){
		this->ec=this->ec->leftNeighbor();
	}
}
/**
 * move the iterator's ec one tile right
 */
void Grid::GridIterator::right()
{
	if(this->ec->rightNeighbor()!=NULL){
		this->ec=this->ec->rightNeighbor();
	}
}
/**
 * @return the ec of the iterator
 */
Tile* Grid::GridIterator::getEc()
{
	return this->ec;
}
/**
 * set the iterator's ec to ec
 */
void Grid::GridIterator::setEc(Tile* ec)
{
	this->ec=ec;
}
/**
 * return true if the iterator's ec has a up neighbor
 */
bool Grid::GridIterator::hasUp()
{
	return(this->ec->upNeighbor()!=NULL);
}
/**
 * return true if the iterator's ec has a down neighbor
 */
bool Grid::GridIterator::hasDown()
{
	return(this->ec->downNeighbor()!=NULL);
}
/**
 * return true if the iterator's ec has a left neighbor
 */
bool Grid::GridIterator::hasLeft()
{
	return(this->ec->leftNeighbor()!=NULL);
}
/**
 * return true if the iterator's ec has a right neighbor
 */
bool Grid::GridIterator::hasRight()
{
	return(this->ec->rightNeighbor()!=NULL);
}

Grid::GridIterator::GridIterator(Grid* g)
{
	this->myGrid=g;
}


Grid::GridIterator::~GridIterator(void)
{
	cout<<"destruction"<<endl;
}
/**
 * @return an iterator over the grid
 */
Grid::GridIterator* Grid::getIterator()
{
	Grid::GridIterator* gi = new Grid::GridIterator(this);
	gi->init();
	return gi;
}
/**
 * initialize the grid iterator
 */
void Grid::GridIterator::init()
{
	cout<<"iterator : init"<<endl;
	this->ec=this->myGrid->firstTile;
}
}
